package com.solution.service;

import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.ejb.EJBException;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;

import org.apache.log4j.Logger;
import org.jboss.annotation.ejb.RemoteBinding;

import sun.misc.BASE64Encoder;

import com.solution.constant.ErrorMessages;
import com.solution.constant.UserManagementErrorMessage;
import com.solution.dao.DAOFactory;
import com.solution.dao.UserInfoDAO;
import com.solution.dao.UserQuestionMappingDAO;
import com.solution.dao.UserRoleDAO;
import com.solution.dao.UserTypeDAO;
import com.solution.exception.DAOException;
import com.solution.exception.ServiceBeanException;
import com.solution.model.UserInfo;
import com.solution.model.UserQuestionMapping;
import com.solution.model.UserRole;
import com.solution.model.UserRoleId;
import com.solution.model.UserType;
import com.solution.util.SearchVO;

/**
 * This class exposes all the services for creation, update, read and
 * deletion of User.
 *
 *
 */
@Stateless
@Remote(UserInfoService.class)
@RemoteBinding(jndiBinding="UserInfoService")
@TransactionManagement(TransactionManagementType.CONTAINER)
public class UserInfoServiceImpl {

	/**
	 * DAO instance.
	 */
	private UserInfoDAO userDao = (UserInfoDAO)DAOFactory.getDAOInstance(UserInfoDAO.class.getName());
	private UserRoleDAO userRoleDao = (UserRoleDAO)DAOFactory.getDAOInstance(UserRoleDAO.class.getName());
	private UserTypeDAO userTypeDao = (UserTypeDAO)DAOFactory.getDAOInstance(UserTypeDAO.class.getName());
	private UserQuestionMappingDAO userQuestionMappingDao = (UserQuestionMappingDAO)DAOFactory.getDAOInstance(UserQuestionMappingDAO.class.getName());
	
	/**
	 * Logger instance.
	 */
	private Logger log = Logger.getLogger(UserInfoServiceImpl.class.getName());
	
	/**
	 * This service creates the User entry in the database after performing
	 * required business logic.
	 * @param userInfo
	 * @return
	 * @throws ServiceBeanException
	 */
	public UserInfo create(UserInfo userInfo) throws ServiceBeanException{
		log.debug("Entering :: UserServiceImpl:create()");
		try{
			UserRole userRole ;
			// Perform business validations.
			// check for the mandatory parameters.
			if(userInfo!=null && userInfo.checkForMandatoryParameters() != null && userInfo.checkForMandatoryParameters().size() > 0){
				String errorMsg = ErrorMessages.MANDATORY_PARAMETER_MISSING_EXCEPTION;
				Iterator<String> iter = userInfo.checkForMandatoryParameters().iterator();
				while(iter.hasNext()){
					errorMsg = errorMsg+", "+iter.next();
				}
				throw new ServiceBeanException(errorMsg);
			}
			// Create the entry in database.
			boolean isUserUnique = userDao.verifyUnique("username",userInfo.getUsername(),null);
			if(!isUserUnique){
				userInfo.setUserExist(!isUserUnique);
				return userInfo;
			}
			userInfo = userDao.create(userInfo);
			
			log.info("The new User created with ID : "+userInfo.getId().longValue());
			
			userRole = new UserRole();
			UserRoleId userRoleId = new UserRoleId();
			userRoleId.setUserInfoId(userInfo.getId());
			userRoleId.setUserRoleTypeId(userInfo.getRoleId());
			userRole.setId(userRoleId);
			userRoleDao.create(userRole);
			log.debug("Exiting :: UserServiceImpl:create()");
			return userInfo;
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_CREATE_EXCEPTION, ex);
			throw new EJBException(ex);
		}
	}
	
	public List<UserInfo> create(List<UserInfo> userInfoList) throws ServiceBeanException{
		if(userInfoList != null && userInfoList.size()>0){
			List<UserInfo> userList = new ArrayList<UserInfo>(userInfoList.size());
			for(UserInfo userInfo:userInfoList){
				userInfo = create(userInfo);
				userList.add(userInfo);
			}
			return userList;
		}
		else{
			throw new ServiceBeanException(ErrorMessages.MANDATORY_PARAMETER_MISSING_EXCEPTION+" userInfoList");
		}
	}
	
	/**
	 * This service updates the User entry in the database after performing
	 * required business logic.
	 * @param userInfo
	 * @return
	 * @throws ServiceBeanException
	 */
	public UserInfo update(UserInfo userInfo) throws ServiceBeanException{
		log.debug("Entering :: UserServiceImpl:update()");
		try{
			// Update the entry in database.
			// check for the mandatory parameters.
			if(userInfo!= null && userInfo.checkForMandatoryParameters() != null && userInfo.checkForMandatoryParameters().size() > 0){
				String errorMsg = ErrorMessages.MANDATORY_PARAMETER_MISSING_EXCEPTION;
				Iterator<String> iter = userInfo.checkForMandatoryParameters().iterator();
				while(iter.hasNext()){
					errorMsg = errorMsg+", "+iter.next();
				}
				throw new ServiceBeanException(errorMsg);
			}
			userInfo = userDao.update(userInfo);
			log.info("The User updated with ID : "+userInfo.getId().longValue());
			log.debug("Exiting :: UserServiceImpl:update()");
			return userInfo;
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_UPDATE_EXCEPTION, ex);
			throw new EJBException(ex);
		}
	}
	
	/**
	 * This service updates the User entry in the database after performing
	 * required business logic.
	 * @param userInfo
	 * @return
	 * @throws ServiceBeanException
	 */
	public UserInfo updateUser(UserInfo userInfo) throws ServiceBeanException{
		log.debug("Entering :: UserServiceImpl:update()");
		try{
			// Update the entry in database.
			UserRole userRole;
			// check for the mandatory parameters.
			if(userInfo != null && userInfo.checkForMandatoryParameters() != null && userInfo.checkForMandatoryParameters().size() > 0){
				String errorMsg = ErrorMessages.MANDATORY_PARAMETER_MISSING_EXCEPTION;
				Iterator<String> iter = userInfo.checkForMandatoryParameters().iterator();
				while(iter.hasNext()){
					errorMsg = errorMsg+", "+iter.next();
				}
				throw new ServiceBeanException(errorMsg);
			}
			userInfo = userDao.update(userInfo);
			userRoleDao.deleteAllRoleForUser(userInfo.getId());
			userTypeDao.deleteAllTypeForUser(userInfo.getId());
			
			userRole = new UserRole();
			UserRoleId userRoleId = new UserRoleId();
			userRoleId.setUserInfoId(userInfo.getId());
			userRoleId.setUserRoleTypeId(userInfo.getRoleId());
			userRole.setId(userRoleId);
			userRoleDao.create(userRole);
			log.debug("Exiting :: UserServiceImpl:Update()");
			return userInfo;
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_UPDATE_EXCEPTION, ex);
			throw new EJBException(ex);
		}
	}
	
	/**
	 * This service reads a user from database based on the primary
	 * key.
	 * @param userInfoId
	 * @return
	 * @throws ServiceBeanException
	 */
	public UserInfo read(Long userInfoId) throws ServiceBeanException{
		try{
			log.debug("Entering :: UserServiceImpl:read()");
			if(userInfoId != null){
				return userDao.read(userInfoId);
			}
			else{
				throw new ServiceBeanException(ErrorMessages.MANDATORY_PARAMETER_MISSING_EXCEPTION+" userInfoId");
			}
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_READ_EXCEPTION, ex);
			throw new EJBException(ex);
		}
	}
	/**
	 * OverLoaded method 
	 * @param userName
	 * @return
	 * @throws ServiceBeanException
	 */
	public UserInfo getUserDetail(String userName) throws ServiceBeanException{
		try{
			log.debug("Entering :: UserServiceImpl:read()");
			if(userName != null){
				SearchVO searchVO = new SearchVO();
				searchVO.addEqualsCaseSensitiveCondition("username", userName);
				List<UserInfo> userList = userDao.search(searchVO);
				return (userList!=null && userList.size() >0)?userList.get(0):null;
			}
			else{
				throw new ServiceBeanException(ErrorMessages.MANDATORY_PARAMETER_MISSING_EXCEPTION+" userName");
			}
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_READ_EXCEPTION, ex);
			throw new EJBException(ex);
		}
	}
	
	/**
	 * This service deletes a User from database based on the primary
	 * key.
	 * @param userInfoId
	 * @throws ServiceBeanException
	 */
	public void delete(Long userInfoId) throws ServiceBeanException{
		try{
			log.debug("Entering :: UserServiceImpl:delete()");
			userDao.delete(userInfoId);
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_READ_EXCEPTION, ex);
			throw new EJBException(ex);
		}
	}
	
	/**
	 * return encrypted password
	 * @param password
	 * @return
	 * @throws Exception
	 */
	public String encryptPassword(String password) throws Exception {
		MessageDigest md = MessageDigest.getInstance("MD5");
		BASE64Encoder encoder = new BASE64Encoder();
	    md.update(password.getBytes("UTF8")); 
	    byte[] digestedPwdBytes = md.digest(); 
	    return new String(encoder.encode(digestedPwdBytes));
	}
	
	/**
	 * Search list of user
	 * @param searchVO
	 * @return
	 * @throws ServiceBeanException
	 */
	public List<UserInfo> searchUser(SearchVO searchVO) throws ServiceBeanException {
		try{
			log.debug("Entering :: UserInfoServiceImpl:searchUser()");
			return (List<UserInfo>)userDao.search(searchVO);
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_READ_EXCEPTION, ex);
			throw new EJBException(ex);
		}		
	}
	
	public Integer countUser(SearchVO searchVO) throws ServiceBeanException {
		try{
			log.debug("Entering :: UserInfoServiceImpl:countUser()");
			return userDao.count(searchVO);
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_READ_EXCEPTION, ex);
			throw new EJBException(ex);
		}		
	}
	
	/**
	 * list of roles of user
	 * @param userID
	 * @return
	 * @throws ServiceBeanException
	 */
	public List<UserRole> getUserRoleList(Long userId) throws ServiceBeanException {
		try{
			log.debug("Entering :: UserInfoServiceImpl:getUserRoleList()");
			if(userId != null){
				UserRole userRole = new UserRole();
				UserInfo userInfo = new UserInfo();
				userInfo.setId(userId);
				userRole.setUserInfo(userInfo);	
				SearchVO searchVO = new SearchVO();
				searchVO.addEqualsCondition("userInfo.id", userId);		
				return userRoleDao.search(searchVO);
			}
			else{
				throw new ServiceBeanException(ErrorMessages.MANDATORY_PARAMETER_MISSING_EXCEPTION+" userId");
			}
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_READ_EXCEPTION, ex);
			throw new EJBException(ex);
		}	
	}

	/**
	 * Validate whether user exist or not
	 * @param userInfo
	 * @return
	 * @throws ServiceBeanException
	 */
	public boolean validateUserPassword(UserInfo userInfo)  throws ServiceBeanException {
		try{
			log.debug("Entering :: UserInfoServiceImpl:validateUserPassword()");
			if(userInfo.getUsername() != null && !"".equals(userInfo.getUsername()) &&
					userInfo.getPassword() != null && !"".equals(userInfo.getPassword())){
				SearchVO searchVO = new SearchVO();
				searchVO.addEqualsCaseSensitiveCondition("username", userInfo.getUsername());
				searchVO.addEqualsCaseSensitiveCondition("password",userInfo.getPassword());
				List<UserInfo> userList = userDao.search(searchVO);
				// user exist if following condition comes true.
				log.debug("Exiting :: UserInfoServiceImpl:validateUserPassword()");
				return (userList!=null && userList.size()>0);
			}
			else{
				throw new ServiceBeanException(ErrorMessages.MANDATORY_PARAMETER_MISSING_EXCEPTION+" username, password");
			}
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_READ_EXCEPTION, ex);
			throw new EJBException(ex);
		}	
	}
	public List<UserType> getUserTypeList(Long userID) throws ServiceBeanException {
		try{
			log.debug("Entering :: UserInfoServiceImpl:getUserTypeList()");
			if(userID != null){
				UserType userType = new UserType();
				UserInfo userInfo = new UserInfo();
				userInfo.setId(userID);
				userType.setUserInfo(userInfo);
				SearchVO searchVO = new SearchVO();
				searchVO.addEqualsCondition("userInfo.id", userID);
				List<UserType> userTypeList = userTypeDao.search(searchVO);			
				return userTypeList;
			}
			else{
				throw new ServiceBeanException(ErrorMessages.MANDATORY_PARAMETER_MISSING_EXCEPTION+" userID");
			}
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_READ_EXCEPTION, ex);
			throw new EJBException(ex);
		}	
	}
	public List<UserQuestionMapping> searchUserQuestionMappings(SearchVO searchVO)throws ServiceBeanException{
		try{
		return userQuestionMappingDao.search(searchVO);
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_QUESTION_FETCH_EXCEPTION, ex);
			throw new EJBException(ex);
		}
		
	}
	public void createUserQuestionMappings(List<UserQuestionMapping> userQuestionMappings) 
		throws ServiceBeanException{
		try{
			log.debug("Entering :: UserInfoServiceImpl:createUserQuestionMappings()");
			// Perform business validations.
			for(UserQuestionMapping userQuestionMapping : userQuestionMappings){
				// check for the mandatory parameters.
				if(userQuestionMapping!=null && userQuestionMapping.checkForMandatoryParameters() != null && userQuestionMapping.checkForMandatoryParameters().size() > 0){
					String errorMsg = ErrorMessages.MANDATORY_PARAMETER_MISSING_EXCEPTION;
					Iterator<String> iter = userQuestionMapping.checkForMandatoryParameters().iterator();
					while(iter.hasNext()){
						errorMsg = errorMsg+", "+iter.next();
					}
					throw new ServiceBeanException(errorMsg);
				}
				else{
					userQuestionMappingDao.create(userQuestionMapping);
				}
			}
		}
		catch(DAOException ex){
			log.error(UserManagementErrorMessage.USER_QUESTION_TYPE_CREATE_EXCEPTION, ex);
			throw new EJBException(ex);
		}
	}
}
